package task.gui;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.custom.ControlEditor;
import org.eclipse.swt.custom.TableCursor;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Display;

import task.ConnectionDescription;
import task.Context;
import task.IDbTask;
import task.ITask;
import util.JdbcUtil;

public class TaskDetailView extends Composite {
	private Label nameLabel = null;
	private Label descriptionLabel = null;
	private Text descriptionArea = null;
	private Button runButton = null;
	private Label actualNameLabel = null;
	private Label imageLabel = null;
	private Combo connectionCombo = null;
	private Label connectionLabel = null;
	private ITask task;
	private Table propsTable;
	private HashMap<String, ConnectionDescription> connMap = new HashMap<String, ConnectionDescription>();
	private ConnectionDescription currCD;
	private Context context;
	public TaskDetailView(Composite parent, int style, ArrayList<ConnectionDescription> conns, Context context) {
		super(parent, style);
		this.context = context;
//		context.runListener = this;
		for (ConnectionDescription cd : conns) {
			connMap.put(cd.getName(), cd);
		}
		initialize(conns);
	}

	private void initialize(ArrayList<ConnectionDescription> conns) {
		GridData gridData11 = new GridData();
		gridData11.horizontalAlignment = org.eclipse.swt.layout.GridData.BEGINNING;
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 3;
		GridData gridData;
		nameLabel = new Label(this, SWT.NONE);
		nameLabel.setText("Name");

		gridData = new GridData();
		gridData.widthHint = 200;
		actualNameLabel = new Label(this, SWT.SHADOW_OUT);
		actualNameLabel.setText(" ");
		actualNameLabel.setFont(new Font(Display.getDefault(), "Tahoma", 10, SWT.BOLD));
		actualNameLabel.setLayoutData(gridData);
		gridData = new GridData();
		gridData.widthHint = 32;
		gridData.heightHint = 32;
		imageLabel = new Label(this, SWT.SHADOW_OUT);
		imageLabel.setLayoutData(gridData);
		descriptionLabel = new Label(this, SWT.NONE);
		descriptionLabel.setText("Description");
		descriptionArea = new Text(this, SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.BORDER | SWT.READ_ONLY);
		descriptionArea.setEditable(false);
		gridData = new GridData();
		gridData.heightHint = 50;
		gridData.horizontalSpan = 3;
		gridData.widthHint = 300;
		descriptionArea.setLayoutData(gridData);
		connectionLabel = new Label(this, SWT.NONE);
		connectionLabel.setText("Connection");
		createConnectionCombo(conns);
		runButton = new Button(this, SWT.NONE);
		runButton.setText("Run");
		ImageData idata = new ImageData(this.getClass().getResourceAsStream("/img/run_exc.gif"));
		Image image = new Image(getParent().getDisplay(), idata);
		runButton.setImage(image);
		runButton.setLayoutData(gridData11);
		runButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() {
			public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
				if (task != null) {
					runButton.setEnabled(false);
					try {
						Map<String, String> props = context.getTaskProperties(task);
						if (task instanceof IDbTask) {
							Connection conn = JdbcUtil.getConnection(currCD.getUrl(), currCD.getUser(), currCD.getPasswd());
							((IDbTask)task).setConnection(conn);
							task.run(props);
							conn.close();
							((IDbTask)task).setConnection(null);
						} else {
							task.run(props);
						}
					} catch (RuntimeException ex) {
						Throwable cause = ex.getCause();
						error(cause != null ? cause : ex, task);
//						cause.printStackTrace();
					} catch (SQLException ex) {
						error(ex, task);
					} catch (ClassNotFoundException ex) {
						error(ex, task);
					}
					runButton.setEnabled(true);
				}
			}
		});
		Label propsLabel = new Label(this, SWT.NONE);
		propsLabel.setText("Needed Properties");
		gridData = new GridData();
		gridData.horizontalSpan = 3;
		propsLabel.setLayoutData(gridData);
		
		propsTable = createPropsTable();
		
		this.setLayout(gridLayout);
		this.setSize(new Point(798, 355));
	}
	private Table createPropsTable() {
		String[] titles = {"Name", "Value", "Default Value", ""};
		final Table table = new Table (this, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION);
		GridData data = new GridData (SWT.FILL, SWT.FILL, true, true);
		data.heightHint = 200;
		data.horizontalSpan = 4;
		table.setLayoutData (data);
		table.setLinesVisible (true);
		table.setHeaderVisible (true);
		for (int i=0; i<titles.length; i++) {
			TableColumn column = new TableColumn (table, SWT.NONE);
			column.setText (titles [i]);
			column.setWidth(76);
		}	
//		for (int i=0 ; i<6 ; i++) {
//			TableItem item = new TableItem (table, SWT.NONE);
//			item.setText(new String[] { "", "", ""});
//		}
		for (int i=0; i<titles.length; i++) {
			table.getColumn (i).pack ();
		}	
		// create a TableCursor to navigate around the table
		final TableCursor cursor = new TableCursor(table, SWT.NONE);
		// create an editor to edit the cell when the user hits "ENTER" 
		// while over a cell in the table
		final ControlEditor editor = new ControlEditor(cursor);
		editor.grabHorizontal = true;
		editor.grabVertical = true;
	
		cursor.addSelectionListener(new SelectionAdapter() {
			// when the TableEditor is over a cell, select the corresponding row in 
			// the table
			public void widgetSelected(SelectionEvent e) {
				table.setSelection(new TableItem[] {cursor.getRow()});
			}
			// when the user hits "ENTER" in the TableCursor, pop up a text editor so that 
			// they can change the text of the cell
			public void widgetDefaultSelected(SelectionEvent e){
				int column = cursor.getColumn();
				if (column != 1) return;
				final Text text = new Text(cursor, SWT.NONE);
				TableItem row = cursor.getRow();
				text.setText(row.getText(column));
				text.addKeyListener(new KeyAdapter() {
					public void keyPressed(KeyEvent e) {
						// close the text editor and copy the data over 
						// when the user hits "ENTER"
						if (e.character == SWT.CR) {
							TableItem row = cursor.getRow();
							int rowNo = table.indexOf(row);
							int column = cursor.getColumn();
							row.setText(column, text.getText());
							context.setTaskValue(task, rowNo, text.getText());
							text.dispose();
						}
						// close the text editor when the user hits "ESC"
						if (e.character == SWT.ESC) {
							text.dispose();
						}
					}

				});
				editor.setEditor(text);
				text.setFocus();
			}
		});
		// Hide the TableCursor when the user hits the "MOD1" or "MOD2" key.
		// This allows the user to select multiple items in the table.
		cursor.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				if (e.keyCode == SWT.MOD1 || 
				    e.keyCode == SWT.MOD2 || 
				    (e.stateMask & SWT.MOD1) != 0 || 
				    (e.stateMask & SWT.MOD2) != 0) {
					cursor.setVisible(false);
				}
			}
		});
		// Show the TableCursor when the user releases the "MOD2" or "MOD1" key.
		// This signals the end of the multiple selection task.
		table.addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent e) {
				if (e.keyCode == SWT.MOD1 && (e.stateMask & SWT.MOD2) != 0) return;
				if (e.keyCode == SWT.MOD2 && (e.stateMask & SWT.MOD1) != 0) return;
				if (e.keyCode != SWT.MOD1 && (e.stateMask & SWT.MOD1) != 0) return;
				if (e.keyCode != SWT.MOD2 && (e.stateMask & SWT.MOD2) != 0) return;
			
				TableItem[] selection = table.getSelection();
				TableItem row = (selection.length == 0) ? table.getItem(table.getTopIndex()) : selection[0];
				table.showItem(row);
				cursor.setSelection(row, 0);
				cursor.setVisible(true);
				cursor.setFocus();
			}
		});
		return table;
	}

	private void error(Throwable e, ITask task) {
		Shell dialog = new Shell (getShell(), SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX
				| SWT.APPLICATION_MODAL);
		dialog.setText ("Error");
		dialog.setImage(getDisplay().getSystemImage(SWT.ICON_ERROR));
		dialog.setSize (400, 200);
		
		GridData gridData = new GridData();
		gridData.horizontalSpan = 2;
		gridData.verticalAlignment = org.eclipse.swt.layout.GridData.FILL;
		gridData.horizontalAlignment = org.eclipse.swt.layout.GridData.FILL;
		gridData.widthHint = -1;
		gridData.heightHint = -1;
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 2;
		dialog.setLayout(gridLayout);
		dialog.setSize(new Point(540, 390));
		Label imageLabel = new Label(dialog, SWT.NONE);
		imageLabel.setImage(getDisplay().getSystemImage(SWT.ICON_ERROR));
		Label textLabel = new Label(dialog, SWT.NONE);
		textLabel.setText("Error when running " + task.getName());
		textLabel.setFont(new Font(Display.getDefault(), "Tahoma", 12, SWT.NORMAL));
		Text textArea = new Text(dialog, SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
		textArea.setEditable(false);
		textArea.setLayoutData(gridData);
		StringWriter sw = new StringWriter();
		PrintWriter out = new PrintWriter(sw);
		e.printStackTrace(out);
		textArea.setText(sw.toString());
		out.close();
		dialog.open ();
	}

	/**
	 * This method initializes connectionCombo	
	 * @param conns 
	 *
	 */
	private void createConnectionCombo(ArrayList<ConnectionDescription> conns) {
		String[] connNames = new String[conns.size()];
		for (int i=0 ; i<conns.size() ; i++) {
			connNames[i] = conns.get(i).getName();
		}
		GridData gridData1 = new GridData();
		gridData1.horizontalAlignment = org.eclipse.swt.layout.GridData.FILL;
		connectionCombo = new Combo(this, SWT.READ_ONLY);
		connectionCombo.setText("Connection");
		connectionCombo.setToolTipText("Name of database connection");
		connectionCombo.setItems(connNames);
		connectionCombo.setLayoutData(gridData1);
		connectionCombo
				.addSelectionListener(new SelectionListener() {
					public void widgetSelected(SelectionEvent e) {
						setConnection();
					}
					public void widgetDefaultSelected(
							org.eclipse.swt.events.SelectionEvent e) {
					}
				});
	}
	public void updateConnections(ArrayList<ConnectionDescription> conns) {
		int ndx = connectionCombo.getSelectionIndex();
		String curr = null;
		if (ndx>=0) {
			curr = connectionCombo.getItem(ndx);
		}
		String[] connNames = new String[conns.size()];
		int newNdx = -1;
		for (int i=0 ; i<conns.size() ; i++) {
			connNames[i] = conns.get(i).getName();
			if (connNames[i].equals(curr)) {
				newNdx = i;
			}
		}
		connectionCombo.setItems(connNames);
		connectionCombo.select(newNdx);
		connectionCombo.redraw();
	}
	public void setTask(ITask task) {
		this.task = task;
		setName(task.getName());
		String desc = task.getDescription();
		setDescription(desc != null ? desc : "");
		setImageData(task.getImageData());
		setNeededProps(task.propertyNames(), task.propertyTypes());
		setConnection();
	}
	public ITask getTask() {
		return task;
	}

	private void setNeededProps(String[] props, Object[] propTypes) {
		if (propTypes == null) {
			propTypes = new Object[props.length];
		}
		propsTable.removeAll();
		String[] localVals = context.getTaskValues(task);
		if (localVals == null || props.length != localVals.length) {
			localVals = new String[props.length];
		}
		for (int i=0 ; i<props.length ; i++) {
			TableItem item = new TableItem (propsTable, SWT.NONE);
			String def = context.getGlobal(props[i]);
			String val = localVals[i];
			String[] tab = new String[]{ props[i], val != null ? val : "", def != null ? def : ""};
			item.setText(tab);
		}
	}

	private void setConnection() {
		int ndx = connectionCombo.getSelectionIndex();
		if (ndx<0) return;
		String connName = connectionCombo.getItem(ndx);
		currCD = connMap.get(connName);
	}
	public void setName(String name) {
		actualNameLabel.setText(name);
		actualNameLabel.redraw();
	}
	public void setDescription(String desc) {
		descriptionArea.setText(desc);
	}
	public void setImageData(ImageData data) {
		Image image;
		if (data != null) {
			image = new Image(getDisplay(), data);
		} else {
			image = null;
		}
		imageLabel.setImage(image);
	}

	public Context getContext() {
		return context;
	}

	public void setContext(Context context) {
		this.context = context;
	}

	public String getCurrCD() {
		return currCD != null ? currCD.getName() : null;
	}

	public void setCurrCD(String connName) {
		currCD = connMap.get(connName);
		if (connName != null) {
			String[] items = connectionCombo.getItems();
			for (int i=0 ; i<items.length ; i++) {
				if (connName.equals(items[i])) {
					connectionCombo.select(i);
					break;
				}
			}
		}
		connectionCombo.redraw();
	}
}  //  @jve:decl-index=0:visual-constraint="10,10"
